const express = require("express");
const multer = require("multer");
const path = require("path");
const fs = require("fs-extra");
const cors = require("cors");

const app = express();
const PORT = process.env.PORT || 12930;

// 中间件配置
app.use(cors());

// 启用JSON解析器用于合并API，但限制大小
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ extended: true, limit: "50mb" }));

// 添加请求大小检查中间件
app.use((req, res, next) => {
  const contentLength = req.headers["content-length"];
  console.log(
    `收到请求: ${req.method} ${req.url}, Content-Length: ${contentLength}`
  );

  if (contentLength && parseInt(contentLength) > 10 * 1024 * 1024 * 1024) {
    // 10GB
    console.log(`请求体过大: ${contentLength} bytes`);
    return res.status(413).json({
      success: false,
      error: "文件过大",
      details: "文件大小超过10GB限制",
      suggestion: "请压缩文件或使用其他传输方式",
    });
  }
  next();
});

app.use(express.static("public"));

// 请求超时处理
app.use((req, res, next) => {
  // 设置30分钟超时
  req.setTimeout(30 * 60 * 1000);
  res.setTimeout(30 * 60 * 1000);

  // 监听超时事件
  req.on("timeout", () => {
    console.error("请求超时:", req.url);
    if (!res.headersSent) {
      res.status(408).json({
        success: false,
        error: "请求超时",
        details: "上传时间过长，请重试",
      });
    }
  });

  next();
});

// 413错误处理中间件
app.use((error, req, res, next) => {
  console.log("检查错误:", {
    status: error.status,
    statusCode: error.statusCode,
    message: error.message,
    code: error.code,
    type: error.type,
  });

  if (
    error.status === 413 ||
    error.statusCode === 413 ||
    error.code === "LIMIT_FILE_SIZE"
  ) {
    console.error("413错误 - 请求体过大:", {
      error: error,
      url: req.url,
      method: req.method,
      contentLength: req.headers["content-length"],
      userAgent: req.headers["user-agent"],
    });
    return res.status(413).json({
      success: false,
      error: "文件过大",
      details: "上传的文件超过服务器限制，请尝试上传较小的文件",
      suggestion: "请检查文件大小是否超过10GB限制",
    });
  }
  next(error);
});

// 全局错误处理中间件
app.use((error, req, res, next) => {
  console.error("全局错误处理:", error);

  // 确保总是返回JSON格式的响应
  if (!res.headersSent) {
    res.status(500).json({
      success: false,
      error: "服务器内部错误",
      details:
        process.env.NODE_ENV === "development" ? error.message : undefined,
    });
  }
});

// 确保上传目录存在
const uploadDir = path.join(__dirname, "uploads");
fs.ensureDirSync(uploadDir);

// 配置multer用于文件上传
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, uploadDir);
  },
  filename: function (req, file, cb) {
    try {
    // 保持原始文件名，添加时间戳避免重名
    const timestamp = Date.now();
      let originalName = file.originalname;

      // 处理文件名编码问题
      try {
        // 尝试从latin1解码到utf8
        originalName = Buffer.from(file.originalname, "latin1").toString(
      "utf8"
    );
      } catch (encodingError) {
        // 如果解码失败，使用原始文件名
        console.warn("文件名编码转换失败，使用原始文件名:", file.originalname);
        originalName = file.originalname;
      }

      // 清理文件名中的特殊字符，避免文件系统问题
      const cleanName = originalName.replace(/[<>:"/\\|?*]/g, "_");

      cb(null, `${timestamp}-${cleanName}`);
    } catch (error) {
      console.error("文件名处理错误:", error);
      // 如果处理失败，使用时间戳作为文件名
      cb(null, `${Date.now()}-unknown_file`);
    }
  },
});

// 配置multer，支持大文件上传
const upload = multer({
  storage: storage,
  limits: {
    fileSize: 1024 * 1024 * 1024 * 10, // 10GB 限制
    fieldSize: 1024 * 1024 * 10, // 10MB 字段大小限制
    fieldNameSize: 100, // 字段名长度限制
    fieldValueSize: 1024 * 1024 * 10, // 字段值长度限制
    fields: 10, // 字段数量限制
    files: 1, // 文件数量限制
    parts: 100, // 部分数量限制
  },
  fileFilter: (req, file, cb) => {
    try {
      // 记录文件信息
      console.log("处理文件:", {
        originalname: file.originalname,
        mimetype: file.mimetype,
        size: file.size,
        encoding: file.encoding,
        fieldname: file.fieldname,
      });

      // 检查文件名
      if (!file.originalname || file.originalname.trim() === "") {
        console.warn("空文件名，使用默认名称");
        file.originalname = "unknown_file";
      }

      // 允许所有文件类型
      cb(null, true);
    } catch (error) {
      console.error("文件过滤器错误:", error);
      cb(error, false);
    }
  },
  onError: (err, next) => {
    console.error("Multer配置错误:", err);
    next(err);
  },
});

// multer错误处理中间件
const handleMulterError = (error, req, res, next) => {
  console.error("Multer错误详情:", {
    name: error.name,
    message: error.message,
    code: error.code,
    stack: error.stack,
  });

  if (error instanceof multer.MulterError) {
    let message = "文件上传失败";
    if (error.code === "LIMIT_FILE_SIZE") {
      message = "文件大小超过限制 (最大5GB)";
    } else if (error.code === "LIMIT_FILE_COUNT") {
      message = "文件数量超过限制";
    } else if (error.code === "LIMIT_UNEXPECTED_FILE") {
      message = "意外的文件字段";
    } else if (error.code === "LIMIT_PART_COUNT") {
      message = "表单字段数量超过限制";
    } else if (error.code === "LIMIT_FIELD_KEY") {
      message = "字段名长度超过限制";
    } else if (error.code === "LIMIT_FIELD_VALUE") {
      message = "字段值长度超过限制";
    } else if (error.code === "LIMIT_FIELD_COUNT") {
      message = "字段数量超过限制";
    }

    return res.status(400).json({
      success: false,
      error: message,
      details: error.message,
    });
  }

  // 处理其他上传相关错误
  if (error.message && error.message.includes("Unexpected end of form")) {
    return res.status(400).json({
      success: false,
      error: "文件上传中断，请重试",
      details: "上传过程中连接中断，可能是网络问题或文件损坏",
    });
  }

  if (error.message && error.message.includes("Multipart")) {
    return res.status(400).json({
      success: false,
      error: "文件格式错误",
      details: "无法解析上传的文件，请检查文件是否完整",
    });
  }

  next(error);
};

// 上传中间件 - 处理连接中断
const uploadMiddleware = (req, res, next) => {
  // 监听请求中断
  req.on("close", () => {
    console.log("客户端断开连接:", req.url);
  });

  req.on("error", (err) => {
    console.error("请求错误:", err);
  });

  // 监听响应中断
  res.on("close", () => {
    console.log("响应连接关闭");
  });

  next();
};

// 简化的文件上传API - 专门处理Linux软件文件
app.post("/api/upload", (req, res) => {
  console.log("开始处理上传请求...");
  console.log("请求头信息:", {
    "content-length": req.headers["content-length"],
    "content-type": req.headers["content-type"],
    "user-agent": req.headers["user-agent"],
  });

  // 检查文件大小
  const contentLength = req.headers["content-length"];
  if (contentLength && parseInt(contentLength) > 10 * 1024 * 1024 * 1024) {
    console.log(`文件过大: ${contentLength} bytes`);
    return res.status(413).json({
      success: false,
      error: "文件过大",
      details: `文件大小 ${Math.round(
        parseInt(contentLength) / 1024 / 1024
      )}MB 超过10GB限制`,
      suggestion: "请压缩文件或使用其他传输方式",
    });
  }

  // 设置更长的超时时间
  req.setTimeout(5 * 60 * 1000); // 5分钟
  res.setTimeout(5 * 60 * 1000); // 5分钟

  // 监听连接状态
  let isConnected = true;
  let uploadStartTime = Date.now();

  req.on("close", () => {
    isConnected = false;
    const duration = Date.now() - uploadStartTime;
    console.log(`客户端连接已关闭，上传持续了 ${duration}ms`);
  });

  req.on("error", (err) => {
    console.error("请求错误:", err);
    isConnected = false;
  });

  // 使用multer处理上传
  upload.single("file")(req, res, (err) => {
    if (err) {
      console.error("Multer处理错误:", err);

      // 特殊处理Unexpected end of form错误
      if (err.message && err.message.includes("Unexpected end of form")) {
        return res.status(400).json({
          success: false,
          error: "文件上传中断",
          details: "上传过程中连接中断，请检查网络连接并重试",
          suggestion: "建议使用较小的文件或检查网络稳定性",
        });
      }

      return handleMulterError(err, req, res, () => {});
    }

    // 检查连接状态
    if (!isConnected) {
      console.log("连接已断开，取消处理");
      return;
    }

    try {
      const uploadDuration = Date.now() - uploadStartTime;
      console.log(`上传完成，耗时: ${uploadDuration}ms`);

      console.log("收到上传请求:", {
        hasFile: !!req.file,
        originalName: req.file?.originalname,
        size: req.file?.size,
        mimetype: req.file?.mimetype,
        duration: uploadDuration,
      });

      if (!req.file) {
        console.error("没有文件被上传");
        return res.status(400).json({
          success: false,
          error: "没有文件被上传",
        });
      }

      let originalName = req.file.originalname;

      // 处理文件名编码问题
      try {
        originalName = Buffer.from(req.file.originalname, "latin1").toString(
          "utf8"
        );
      } catch (encodingError) {
        console.warn(
          "文件名编码转换失败，使用原始文件名:",
          req.file.originalname
        );
        originalName = req.file.originalname;
      }

      const fileInfo = {
        id: Date.now().toString(),
        originalName: originalName,
        filename: req.file.filename,
        size: req.file.size,
        mimetype: req.file.mimetype,
        uploadTime: new Date().toISOString(),
        path: req.file.path,
        uploadDuration: uploadDuration,
      };

      console.log("文件上传成功:", fileInfo);

      res.json({
        success: true,
        message: "文件上传成功",
        file: fileInfo,
        uploadDuration: uploadDuration,
      });
    } catch (error) {
      console.error("文件上传错误:", error);
      res.status(500).json({
        success: false,
        error: "文件上传失败",
        details: error.message,
      });
    }
  });
});

// 大文件上传API - 专门处理Linux软件等大文件
app.post("/api/upload-large", (req, res) => {
  console.log("开始处理大文件上传请求...");

  // 设置更长的超时时间
  req.setTimeout(2 * 60 * 60 * 1000); // 2小时
  res.setTimeout(2 * 60 * 60 * 1000); // 2小时

  // 监听连接状态
  let isConnected = true;
  let uploadStartTime = Date.now();

  req.on("close", () => {
    isConnected = false;
    const duration = Date.now() - uploadStartTime;
    console.log(`客户端连接已关闭，上传持续了 ${duration}ms`);
  });

  req.on("error", (err) => {
    console.error("请求错误:", err);
    isConnected = false;
  });

  // 使用multer处理上传
  upload.single("file")(req, res, (err) => {
    if (err) {
      console.error("大文件上传错误:", err);

      // 特殊处理各种错误
      if (err.message && err.message.includes("Unexpected end of form")) {
        return res.status(400).json({
          success: false,
          error: "文件上传中断",
          details: "上传过程中连接中断，这通常发生在网络不稳定或文件过大时",
          suggestion: "请检查网络连接，或尝试分块上传大文件",
        });
      }

      if (err.message && err.message.includes("LIMIT_FILE_SIZE")) {
        return res.status(413).json({
          success: false,
          error: "文件过大",
          details: "文件大小超过10GB限制",
          suggestion: "请压缩文件或使用其他传输方式",
        });
      }

      return res.status(400).json({
        success: false,
        error: "上传失败",
        details: err.message,
        suggestion: "请重试或联系管理员",
      });
    }

    // 检查连接状态
    if (!isConnected) {
      console.log("连接已断开，取消处理");
      return;
    }

    try {
      const uploadDuration = Date.now() - uploadStartTime;
      console.log(`大文件上传完成，耗时: ${uploadDuration}ms`);

      console.log("收到上传请求:", {
        hasFile: !!req.file,
        originalName: req.file?.originalname,
        size: req.file?.size,
        mimetype: req.file?.mimetype,
        duration: uploadDuration,
      });

    if (!req.file) {
        console.error("没有文件被上传");
        return res.status(400).json({
          success: false,
          error: "没有文件被上传",
        });
      }

      let originalName = req.file.originalname;

      // 处理文件名编码问题
      try {
        originalName = Buffer.from(req.file.originalname, "latin1").toString(
          "utf8"
        );
      } catch (encodingError) {
        console.warn(
          "文件名编码转换失败，使用原始文件名:",
          req.file.originalname
        );
        originalName = req.file.originalname;
    }

    const fileInfo = {
      id: Date.now().toString(),
        originalName: originalName,
        filename: req.file.filename,
        size: req.file.size,
        mimetype: req.file.mimetype,
        uploadTime: new Date().toISOString(),
        path: req.file.path,
        uploadDuration: uploadDuration,
      };

      console.log("大文件上传成功:", fileInfo);

      res.json({
        success: true,
        message: "大文件上传成功",
        file: fileInfo,
        uploadDuration: uploadDuration,
      });
    } catch (error) {
      console.error("大文件上传处理错误:", error);
      res.status(500).json({
        success: false,
        error: "文件上传失败",
        details: error.message,
      });
    }
  });
});

// 备用上传API（如果上面的有问题）
app.post(
  "/api/upload-backup",
  uploadMiddleware,
  upload.single("file"),
  handleMulterError,
  (req, res) => {
    try {
      console.log("收到上传请求:", {
        hasFile: !!req.file,
        originalName: req.file?.originalname,
        size: req.file?.size,
        mimetype: req.file?.mimetype,
      });

      if (!req.file) {
        console.error("没有文件被上传");
        return res.status(400).json({ error: "没有文件被上传" });
      }

      let originalName = req.file.originalname;

      // 处理文件名编码问题
      try {
        originalName = Buffer.from(req.file.originalname, "latin1").toString(
        "utf8"
        );
      } catch (encodingError) {
        console.warn(
          "文件名编码转换失败，使用原始文件名:",
          req.file.originalname
        );
        originalName = req.file.originalname;
      }

      const fileInfo = {
        id: Date.now().toString(),
        originalName: originalName,
      filename: req.file.filename,
      size: req.file.size,
      mimetype: req.file.mimetype,
      uploadTime: new Date().toISOString(),
      path: req.file.path,
    };

      console.log("文件上传成功:", fileInfo);

    res.json({
      success: true,
      message: "文件上传成功",
      file: fileInfo,
    });
  } catch (error) {
    console.error("文件上传错误:", error);
      res.status(500).json({
        success: false,
        error: "文件上传失败",
        details: error.message,
      });
    }
  }
);

// 获取文件列表API
app.get("/api/files", async (req, res) => {
  try {
    const files = await fs.readdir(uploadDir);
    const fileList = [];

    for (const filename of files) {
      const filePath = path.join(uploadDir, filename);
      const stats = await fs.stat(filePath);

      // 解析文件名（移除时间戳前缀）
      const originalName = filename.replace(/^\d+-/, "");

      fileList.push({
        id: filename,
        originalName: originalName,
        filename: filename,
        size: stats.size,
        uploadTime: stats.birthtime.toISOString(),
        path: filePath,
      });
    }

    // 按上传时间倒序排列
    fileList.sort((a, b) => new Date(b.uploadTime) - new Date(a.uploadTime));

    res.json({
      success: true,
      files: fileList,
    });
  } catch (error) {
    console.error("获取文件列表错误:", error);
    res.status(500).json({ error: "获取文件列表失败" });
  }
});

// 文件下载API
app.get("/api/download/:filename", (req, res) => {
  try {
    const filename = req.params.filename;
    const filePath = path.join(uploadDir, filename);

    // 检查文件是否存在
    if (!fs.existsSync(filePath)) {
      return res.status(404).json({ error: "文件不存在" });
    }

    // 获取原始文件名（移除时间戳前缀）
    const originalName = filename.replace(/^\d+-/, "");

    // 设置响应头
    res.setHeader(
      "Content-Disposition",
      `attachment; filename*=UTF-8''${encodeURIComponent(originalName)}`
    );
    res.setHeader("Content-Type", "application/octet-stream");

    // 发送文件
    res.sendFile(filePath);
  } catch (error) {
    console.error("文件下载错误:", error);
    res.status(500).json({ error: "文件下载失败" });
  }
});

// 删除文件API
app.delete("/api/files/:filename", async (req, res) => {
  try {
    const filename = req.params.filename;
    const filePath = path.join(uploadDir, filename);

    // 检查文件是否存在
    if (!(await fs.pathExists(filePath))) {
      return res.status(404).json({ error: "文件不存在" });
    }

    // 删除文件
    await fs.remove(filePath);

    res.json({
      success: true,
      message: "文件删除成功",
    });
  } catch (error) {
    console.error("文件删除错误:", error);
    res.status(500).json({ error: "文件删除失败" });
  }
});

// 分片上传目录
const chunkDir = path.join(__dirname, "chunks");
fs.ensureDirSync(chunkDir);

// 分片上传API - 上传单个分片
app.post("/api/upload-chunk", (req, res) => {
  console.log("开始处理分片上传请求...");

  const { filename, chunkIndex, totalChunks, fileSize } = req.query;

  if (!filename || chunkIndex === undefined || totalChunks === undefined) {
    return res.status(400).json({
      success: false,
      error: "缺少必要参数",
      details: "需要 filename, chunkIndex, totalChunks 参数",
    });
  }

  console.log("分片信息:", {
    filename,
    chunkIndex,
    totalChunks,
    fileSize,
    contentLength: req.headers["content-length"],
  });

  // 创建分片文件路径
  const chunkFilename = `${filename}.chunk.${chunkIndex}`;
  const chunkPath = path.join(chunkDir, chunkFilename);

  // 设置超时时间
  req.setTimeout(2 * 60 * 1000); // 2分钟
  res.setTimeout(2 * 60 * 1000);

  let isResponseSent = false;
  let writeStream = null;

  try {
    // 使用流式写入
    writeStream = fs.createWriteStream(chunkPath);

    // 监听数据传输
    let bytesReceived = 0;
    req.on("data", (chunk) => {
      bytesReceived += chunk.length;
    });

    req.pipe(writeStream);

    writeStream.on("finish", () => {
      if (!isResponseSent) {
        isResponseSent = true;
        console.log(
          `分片 ${chunkIndex}/${totalChunks} 上传完成: ${chunkFilename} (${bytesReceived} bytes)`
        );
        res.json({
          success: true,
          message: `分片 ${chunkIndex} 上传成功`,
          chunkIndex: parseInt(chunkIndex),
          totalChunks: parseInt(totalChunks),
          bytesReceived: bytesReceived,
        });
      }
    });

    writeStream.on("error", (err) => {
      console.error("分片写入错误:", err);
      if (writeStream && !writeStream.destroyed) {
        writeStream.destroy();
      }
      if (!isResponseSent) {
        isResponseSent = true;
        res.status(500).json({
          success: false,
          error: "分片上传失败",
          details: err.message,
        });
      }
    });

    req.on("error", (err) => {
      console.error("请求错误:", err);
      if (writeStream && !writeStream.destroyed) {
        writeStream.destroy();
      }
      // 删除不完整的分片文件
      fs.remove(chunkPath).catch((e) => console.error("删除分片失败:", e));

      if (!isResponseSent) {
        isResponseSent = true;
        res.status(500).json({
          success: false,
          error: "连接中断",
          details: err.message,
          canRetry: true,
        });
      }
    });

    req.on("aborted", () => {
      console.error("请求被中止:", chunkFilename);
      if (writeStream && !writeStream.destroyed) {
        writeStream.destroy();
      }
      // 删除不完整的分片文件
      fs.remove(chunkPath).catch((e) => console.error("删除分片失败:", e));
    });
  } catch (error) {
    console.error("分片上传异常:", error);
    if (writeStream && !writeStream.destroyed) {
      writeStream.destroy();
    }
    if (!isResponseSent) {
      isResponseSent = true;
      res.status(500).json({
        success: false,
        error: "分片上传失败",
        details: error.message,
      });
    }
  }
});

// 分片合并API
app.post("/api/merge-chunks", async (req, res) => {
  try {
    const { filename, totalChunks, originalName } = req.body;

    if (!filename || !totalChunks) {
      return res.status(400).json({
        success: false,
        error: "缺少必要参数",
        details: "需要 filename 和 totalChunks 参数",
      });
    }

    console.log("开始合并分片:", { filename, totalChunks, originalName });

    // 检查所有分片是否存在
    const missingChunks = [];
    for (let i = 0; i < totalChunks; i++) {
      const chunkPath = path.join(chunkDir, `${filename}.chunk.${i}`);
      if (!(await fs.pathExists(chunkPath))) {
        missingChunks.push(i);
      }
    }

    if (missingChunks.length > 0) {
      return res.status(400).json({
        success: false,
        error: "分片不完整",
        details: `缺少分片: ${missingChunks.join(", ")}`,
      });
    }

    // 创建最终文件路径
    const timestamp = Date.now();
    const finalFilename = `${timestamp}-${originalName || filename}`;
    const finalPath = path.join(uploadDir, finalFilename);

    // 合并分片
    const writeStream = fs.createWriteStream(finalPath);

    for (let i = 0; i < totalChunks; i++) {
      const chunkPath = path.join(chunkDir, `${filename}.chunk.${i}`);
      const chunkData = await fs.readFile(chunkPath);
      writeStream.write(chunkData);
    }

    writeStream.end();

    writeStream.on("finish", async () => {
      try {
        // 清理分片文件
        for (let i = 0; i < totalChunks; i++) {
          const chunkPath = path.join(chunkDir, `${filename}.chunk.${i}`);
          await fs.remove(chunkPath);
        }

        // 获取文件信息
        const stats = await fs.stat(finalPath);
        const fileInfo = {
          id: timestamp.toString(),
          originalName: originalName || filename,
          filename: finalFilename,
          size: stats.size,
          mimetype: "application/octet-stream",
          uploadTime: new Date().toISOString(),
          path: finalPath,
        };

        console.log("分片合并完成:", fileInfo);

        res.json({
          success: true,
          message: "文件合并成功",
          file: fileInfo,
        });
      } catch (error) {
        console.error("清理分片文件错误:", error);
        res.status(500).json({
          success: false,
          error: "清理分片文件失败",
          details: error.message,
        });
      }
    });

    writeStream.on("error", (err) => {
      console.error("合并文件错误:", err);
      res.status(500).json({
        success: false,
        error: "文件合并失败",
        details: err.message,
      });
    });
  } catch (error) {
    console.error("合并分片错误:", error);
    res.status(500).json({
      success: false,
      error: "合并分片失败",
      details: error.message,
    });
  }
});

// 检查分片状态API
app.get("/api/chunk-status/:filename", async (req, res) => {
  try {
    const { filename } = req.params;
    const { totalChunks } = req.query;

    if (!totalChunks) {
      return res.status(400).json({
        success: false,
        error: "缺少 totalChunks 参数",
      });
    }

    const uploadedChunks = [];
    const missingChunks = [];

    for (let i = 0; i < parseInt(totalChunks); i++) {
      const chunkPath = path.join(chunkDir, `${filename}.chunk.${i}`);
      if (await fs.pathExists(chunkPath)) {
        uploadedChunks.push(i);
      } else {
        missingChunks.push(i);
      }
    }

    res.json({
      success: true,
      uploadedChunks,
      missingChunks,
      progress: (uploadedChunks.length / parseInt(totalChunks)) * 100,
    });
  } catch (error) {
    console.error("检查分片状态错误:", error);
    res.status(500).json({
      success: false,
      error: "检查分片状态失败",
      details: error.message,
    });
  }
});

// 启动服务器
app.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}`);
  console.log(`上传目录: ${uploadDir}`);
  console.log(`分片目录: ${chunkDir}`);
});
